﻿#ifndef MODBUSTCP_H
#define MODBUSTCP_H

//Macro
#define MAXSLAVENUMBER 247    //从机地址个数最大为247

#define ADDRESS_MIN 0  //线圈和寄存器的地址最小值
#define ADDRESS_MAX 65535  //线圈和寄存器的地址最大值

#define READ_COIL_MINNUM 1  //请求报文读取线圈个数的最小值
#define READ_COIL_MAXNUM 2000  //请求报文读取线圈个数的最大值
#define READ_REGISTER_MINNUM 1 //请求报文读取寄存器个数的最小值
#define READ_REGISTER_MAXNUM 125 //请求报文读取寄存器个数的最大值

#define WRITE_COIL_MINNUM 1  //请求报文写入线圈个数的最小值
#define WRITE_COIL_MAXNUM 1968  //请求报文写入线圈个数的最大值
#define WRITE_REGISTER_MINNUM 1 //请求报文写入寄存器个数的最小值
#define WRITE_REGISTER_MAXNUM 123 //请求报文写入寄存器个数的最大值
#define WRITE_REGISTER_VALUE_MINNUM 0 //请求报文写入寄存器数值的最小值
#define WRITE_REGISTER_VALUE_MAXNUM 65535 //请求报文写入寄存器数值的最大值

#define REQUEST_MESSAGE_LENGTH_0X01_0X03 12 //0X01或0X03请求报文长度

//Basic
#include <QObject>

//Demand
#include "networkcommunication.h"

class ModbusTCP : public NetworkCommunication
{
    Q_OBJECT
public:
    ModbusTCP(networkParameters netPara);
    virtual ~ModbusTCP(){}

    //ModusTCP请求报文公共信息结构体
    typedef struct ModbusTcpBasicInformation
    {
        //事务元标识符
        quint16 transactionIdenti;
        //协议标识符
        quint16 protocolIdenti = 0;
        //基础长度(6)
        quint16 length = 6;

        //单元标识符
        quint8 unitIdenti;
        //功能码
        quint8 funcCode;
        //起始地址
        quint16 beginAddr;
        //数量
        quint16 num;
    }ModbusTcpBasicInformation;

    //TCP主站发送请求报文函数
    /*1.
     * 参数1：ModusTCP请求报文公共信息结构体
     * 返回：true：发送成功
     *      false：发送失败
     * */
    bool TCPRequestMessageSend(const ModbusTcpBasicInformation &MTBasicInfo);
    /*2.
     * 参数1：ModusTCP请求报文公共信息结构体
     * 参数2：写入字节数组
     * 返回：true：发送成功
     *      false：发送失败
     * */
    bool TCPRequestMessageSend(const ModbusTcpBasicInformation &MTBasicInfo, const QByteArray &byteArr);

protected:
    /*解析响应报文
     * 参数：需要解析的响应报文
     * 返回：true：解析成功
     *      false：解析失败
     * */
    bool TCPAnalysisMessage(const QByteArray &receiveMessageArr, const QByteArray &requestMessageArr);

    /*报文合法性判断函数
     * 参数1：需要判断的报文数组
     * 参数2：发送的请求报文数组
     * 返回：true：响应报文合法
     *       false：响应报文非法
     * */
    bool MessageLegalJudge(const QByteArray &MessageArr, const QByteArray &requestMessageArr);

    /*0X01功能码响应报文处理函数
     * 参数1：0X01功能码响应报文
     * 参数2：0X01功能码请求报文
     * 返回：true：处理成功
     *      false：处理失败
     * */
    bool TCP0X01FuncCodeProcess(const QByteArray &MessageArr, const QByteArray &requestMessageArr, QString &readData);

    /*0X03功能码报文处理函数
     * 参数1：0X03功能码响应报文
     * 参数2：0X03功能码请求报文
     * 返回：true：处理成功
     *      false：处理失败
     * */
    bool TCP0X03FuncCodeProcess(const QByteArray &MessageArr, const QByteArray &requestMessageArr, QString &readData);

    /*0X0f功能码报文处理函数
     * 参数1：0X0f功能码响应报文
     * 参数2：0X0f功能码请求报文
     * 返回：true：处理成功
     *      false：处理失败
     * */
    bool TCP0X0fFuncCodeProcess(const QByteArray &MessageArr, const QByteArray &requestMessageArr);

    /*0X10功能码报文处理函数
     * 参数1：0X10功能码响应报文
     * 参数2：0X10功能码请求报文
     * 返回：true：处理成功
     *      false：处理失败
     * */
    bool TCP0X10FuncCodeProcess(const QByteArray &MessageArr, const QByteArray &requestMessageArr);

    /*功能码合法性判断函数
     * 参数：标准的目标ModbusTcp报文
     * 返回：true：功能码合法
     *      false：功能码不合法
     * */
    bool FuncCodeLegalJudge(const QByteArray &MessageArr);

    //异常报文处理函数
    /*1.
     * 参数1：异常报文数组
     * 参数2：解析出的异常消息字符串
     * 返回：void
     * */
    void TCPExceptionCodeProcess(const QByteArray &MessageArr, QString &exceptionPrompt);
    /*2.
     * 参数1：异常报文数组
     * 返回：解析出的异常消息字符串
     * */
    QString TCPExceptionCodeProcess(const QByteArray &MessageArr);

    //异常码判断函数
    /*1.
     * 参数1：异常码
     * 参数2：解析出的异常码消息字符串
     * 返回：void
     * */
    void TCPExceptionCodeJudge(const quint8 excCode, QString &exceptionCodePrompt);
    /*2.
     * 参数1：异常码
     * 返回：解析出的异常码消息字符串
     * */
    QString TCPExceptionCodeJudge(const quint8 excCode);

    //获取当前读出数据操作获得的报文字符串（0X01/0X03)
    /*1.
     * 参数：接收字符串容器
     * 返回：void
     * */
    void GetReadMessage(QString &readMess);
    /*2.
     * 参数：空
     * 返回：当前读出数据操作获得的报文字符串
     * */
    QString GetReadMessage();


private:
    //声明ModbusTcp报文基础信息结构体
    ModbusTcpBasicInformation basicInfo;
    //读出数据操作获得的报文字符串（0X01/0X03)
    QString readMessage = "";
    //写入数据操作报文数组（0X0f/0X10)
    QByteArray writeMessage = NULL;
    //MBAP事务元标识符
    quint16 transactionIdentifier = 0;

    //读输出线圈0x01和读输出寄存器0x03请求报文构建函数
    void RequestMessage0x010x03Build(QByteArray &requestMess);

    //写多个输出线圈0x0F和写多个输出寄存器0x10请求报构建函数
    void RequestMessage0x0F0x10Build(QByteArray &requestMess);

};

#endif // MODBUSTCP_H
